/*           Copyright(c) 2005-2008 Dave Sexton            *
 *                   HtmlEditor Control                    *
 * http://www.codeplex.com/DocProject/Project/License.aspx *
 ***********************************************************/
using System;
using System.Collections.Generic;
using System.Text;
using System.Windows.Forms;
using mshtml;
using System.Drawing;

namespace DaveSexton.Controls
{
	public enum DataTransferReason
	{
		Success, 
		Aborted, 
		Error
	}

	public sealed class HtmlEvent
	{
		#region Public Properties
		#region IHTMLEventObj
		public MouseButtons Buttons
		{
			get
			{
				if (args != null)
					return args.MouseButtonsPressed;
				else
					switch (evObj.button)
					{
						case 1:
							return MouseButtons.Left;
						case 2:
							return MouseButtons.Right;
						case 3:
							return MouseButtons.Left | MouseButtons.Right;
						case 4:
							return MouseButtons.Middle;
						case 5:
							return MouseButtons.Left | MouseButtons.Middle;
						case 6:
							return MouseButtons.Right | MouseButtons.Middle;
						case 7:
							return MouseButtons.Left | MouseButtons.Right | MouseButtons.Middle;
						default:
							return MouseButtons.None;
					}
			}
		}

		public Keys ModifierKeys
		{
			get
			{
				if (args != null)
				{
					return ((args.ShiftKeyPressed) ? Keys.Shift : Keys.None)
						| ((args.CtrlKeyPressed) ? Keys.Control : Keys.None)
						| ((args.AltKeyPressed) ? Keys.Alt : Keys.None);
				}
				else
				{
					return ((evObj.shiftKey) ? Keys.Shift : Keys.None)
						 | ((evObj.ctrlKey) ? Keys.Control : Keys.None)
						 | ((evObj.altKey) ? Keys.Alt : Keys.None);
				}
			}
		}

		public Keys KeyCode
		{
			get
			{
				return (args != null) ? (Keys) args.KeyPressedCode : (Keys) evObj.keyCode;
			}
		}

		public bool Alt
		{
			get
			{
				return (args != null) ? args.AltKeyPressed : evObj.altKey;
			}
		}

		public bool Shift
		{
			get
			{
				return (args != null) ? args.ShiftKeyPressed : evObj.shiftKey;
			}
		}

		public bool Ctrl
		{
			get
			{
				return (args != null) ? args.CtrlKeyPressed : evObj.ctrlKey;
			}
		}

		public object DomEvent
		{
			get
			{
				return evObj;
			}
		}

		public Point ScreenLocation
		{
			get
			{
				return new Point(evObj.screenX, evObj.screenY);
			}
		}

		public Point Location
		{
			get
			{
				return (args != null) ? args.MousePosition : new Point(evObj.x, evObj.y);
			}
		}

		public Point OffsetLocation
		{
			get
			{
				return (args != null) ? args.OffsetMousePosition : new Point(evObj.offsetX, evObj.offsetY);
			}
		}

		public Point ClientLocation
		{
			get
			{
				return (args != null) ? args.ClientMousePosition : new Point(evObj.clientX, evObj.clientY);
			}
		}

		public bool CancelBubble
		{
			get
			{
				return (args != null) ? !args.BubbleEvent : evObj.cancelBubble;
			}
			set
			{
				if (args != null)
					args.BubbleEvent = !value;
				else
					evObj.cancelBubble = value;
			}
		}

		public object SourceFilter
		{
			get
			{
				return evObj.srcFilter;
			}
		}

		public string Qualifier
		{
			get
			{
				return evObj.qualifier;
			}
		}

		public DataTransferReason Reason
		{
			get
			{
				return (DataTransferReason) evObj.reason;
			}
		}

		public bool ReturnValue
		{
			get
			{
				return (args != null) ? args.ReturnValue : (bool) evObj.returnValue;
			}
			set
			{
				if (args != null)
					args.ReturnValue = value;
				else
					evObj.returnValue = value;
			}
		}

		public string EventType
		{
			get
			{
				return (args != null) ? args.EventType : evObj.type;
			}
		}

		public object SourceDomElement
		{
			get
			{
				return evObj.srcElement;
			}
			set
			{
				// read/write in explorer 5 +
				evObj2.srcElement = (IHTMLElement) value;
			}
		}

		public object FromDomElement
		{
			get
			{
				return (args != null) ? args.FromElement.DomElement : evObj.fromElement;
			}
			set
			{
				// read/write in explorer 5 +
				evObj2.fromElement = (IHTMLElement) value;
			}
		}

		public object ToDomElement
		{
			get
			{
				return (args != null) ? args.ToElement.DomElement : evObj.toElement;
			}
			set
			{
				// read/write in explorer 5 +
				evObj2.toElement = (IHTMLElement) value;
			}
		}

		public HtmlElement SourceElement
		{
			get
			{
				if (sourceElement == null)
					sourceElement = HtmlEditor.FindElement(document, evObj.srcElement);

				return sourceElement;
			}
			set
			{
				// read/write in explorer 5 +
				evObj2.srcElement = (IHTMLElement) ((value != null) ? value.DomElement : null);
			}
		}

		public HtmlElement FromElement
		{
			get
			{
				if (fromElement == null)
					fromElement = (args != null) ? args.FromElement : HtmlEditor.FindElement(document, evObj.fromElement);

				return fromElement;
			}
			set
			{
				// read/write in explorer 5 +
				evObj2.fromElement = (IHTMLElement) ((value != null) ? value.DomElement : null);
			}
		}

		public HtmlElement ToElement
		{
			get
			{
				if (toElement == null)
					toElement = (args != null) ? args.ToElement : HtmlEditor.FindElement(document, evObj.toElement);

				return toElement;
			}
			set
			{
				// read/write in explorer 5 +
				evObj2.toElement = (IHTMLElement) ((value != null) ? value.DomElement : null);
			}
		}
		#endregion

		#region IHTMLEventObj2
		public object Bookmarks
		{
			get
			{
				return evObj2.bookmarks;
			}
		}

		public IEnumerable<HtmlElement> BoundElements
		{
			get
			{
				foreach (IHTMLElement element in evObj2.boundElements)
					yield return HtmlEditor.FindElement(document, element);
			}
		}

		public string DataField
		{
			get
			{
				return evObj2.dataFld;
			}
		}

		public HtmlDataTransfer DataTransfer
		{
			get
			{
				if (transerData != null)
					return transerData;

				IHTMLDataTransfer data = evObj2.dataTransfer;

				if (data == null)
					return null;
				else
					return transerData = new HtmlDataTransfer(data);
			}
		}

		public string PropertyName
		{
			get
			{
				return evObj2.propertyName;
			}
		}

    [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "Recordset")]
		public object Recordset
		{
			get
			{
				return evObj2.recordset;
			}
		}

		public Uri SourceUrn
		{
			get
			{
				return (string.IsNullOrEmpty(evObj2.srcUrn)) ? null : new Uri(evObj2.srcUrn);
			}
		}
		#endregion

		#region IHTMLEventObj3
		public bool AltLeft
		{
			get
			{
				return evObj3.altLeft;
			}
		}

		public bool CtrlLeft
		{
			get
			{
				return evObj3.ctrlLeft;
			}
		}

		public bool ShiftLeft
		{
			get
			{
				return evObj3.shiftLeft;
			}
		}

		public int BehaviorCookie
		{
			get
			{
				return evObj3.behaviorCookie;
			}
		}

		public int BehaviorPart
		{
			get
			{
				return evObj3.behaviorPart;
			}
		}

		public bool ContentOverflow
		{
			get
			{
				return evObj3.contentOverflow;
			}
		}

		public string NextPage
		{
			get
			{
				return evObj3.nextPage;
			}
		}
		#endregion

		#region IHTMLEventObj4
		public int MouseWheel
		{
			get
			{
				return evObj4.wheelDelta;
			}
		}
		#endregion
		#endregion

		#region Private / Protected
		private HtmlElement sourceElement, fromElement, toElement;
		private HtmlDataTransfer transerData;
		private readonly HtmlDocument document;
		private readonly HtmlElementEventArgs args;
		private readonly IHTMLEventObj evObj;
		private readonly IHTMLEventObj2 evObj2;
		private readonly IHTMLEventObj3 evObj3;
		private readonly IHTMLEventObj4 evObj4;
		#endregion

		#region Constructors
		/// <summary>
		/// Constructs a new instance of the <see cref="HtmlEvent" /> class.
		/// </summary>
		internal HtmlEvent(HtmlDocument document, IHTMLEventObj evObj, HtmlElementEventArgs baseArgs)
			: this(document, evObj)
		{
			this.args = baseArgs;
		}

		/// <summary>
		/// Constructs a new instance of the <see cref="HtmlEvent" /> class.
		/// </summary>
		internal HtmlEvent(HtmlDocument document, IHTMLEventObj evObj)
		{
			if (document == null)
				throw new ArgumentNullException("document");

			if (evObj == null)
				throw new ArgumentNullException("evObj");

			this.document = document;
			this.evObj = evObj;
			this.evObj2 = (IHTMLEventObj2) evObj;
			this.evObj3 = (IHTMLEventObj3) evObj;
			this.evObj4 = (IHTMLEventObj4) evObj;
		}
		#endregion

		#region Methods
    public static HtmlEvent Create(HtmlDocument document, object htmlEvent)
		{
      return new HtmlEvent(document, (IHTMLEventObj) htmlEvent);
		}

    public static HtmlEvent Create(HtmlDocument document, object htmlEvent, HtmlElementEventArgs baseArgs)
		{
      return new HtmlEvent(document, (IHTMLEventObj) htmlEvent, baseArgs);
		}
		#endregion
	}
}
